﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
using WeiXinSDK.Core;

namespace WeiXinSDK
{
    public class WeiXinAPI
    {
        /// <summary>
        /// 通过微信接口获取access token
        /// </summary>
        /// <returns></returns>
        public static string GetAccessToken()
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", WeiXinConfig.AppID, WeiXinConfig.Appsecret);
            HttpWebResponse pos = HttpRequest.CreateGetHttpResponse(url);
            StreamReader sr = new StreamReader(pos.GetResponseStream(), Encoding.UTF8);
            string resultStr = sr.ReadToEnd().Trim();
            DataModel.AccessToken result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.AccessToken>(resultStr);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("GetAccessToken ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("GetAccessToken ==> 请求结果：{0}", result.ToString());
                return string.Empty;
            }
            else
            {
                return result.access_token;
            }
        }

        /// <summary>
        /// 通过授权页面获得微信用户的OpenId
        /// </summary>
        /// <param name="Code"></param>
        /// <returns></returns>
        public static string GetAuthorizationOpenId(string Code)
        {
            string url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", WeiXinConfig.AppID, WeiXinConfig.Appsecret, Code);
            HttpWebResponse pos = HttpRequest.CreateGetHttpResponse(url);
            StreamReader sr = new StreamReader(pos.GetResponseStream(), Encoding.UTF8);
            string resultStr = sr.ReadToEnd().Trim();
            DataModel.AuthorizationToken result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.AuthorizationToken>(resultStr);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("GetAuthorizationOpenId ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("GetAuthorizationOpenId ==> 请求结果：{0}", result.ToString());
                return string.Empty;
            }
            else
            {
                return result.openid;
            }
        }

        /// <summary>
        /// 获得微信用户信息
        /// </summary>
        /// <param name="OpenId"></param>
        /// <returns></returns>
        public static DataModel.UserInfo GetUserInfo(string OpenId)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", WeiXinConfig.AccessToken, OpenId);
            HttpWebResponse pos = HttpRequest.CreateGetHttpResponse(url);
            StreamReader sr = new StreamReader(pos.GetResponseStream(), Encoding.UTF8);
            string resultStr = sr.ReadToEnd().Trim();
            JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
            DataModel.UserInfo result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.UserInfo>(resultStr);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("GetUserInfo ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("GetUserInfo ==> 请求结果：{0}", result.ToString());
                return null;
            }
            else
            {
                return result;
            }
        }

        /// <summary>
        /// 长链接转换短链接
        /// </summary>
        /// <param name="Url">长链接</param>
        /// <param name="Output">返回信息，成功返回短链接，失败返回失败信息</param>
        /// <returns></returns>
        public static bool ConvertShortUrl(string Url, out string Output)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/shorturl?access_token={0}", WeiXinConfig.AccessToken);

            IDictionary<string, string> parameters = new Dictionary<string, string>()
            {
                {"action", "long2short"},
                {"long_url ", Url}
            };
            HttpWebResponse response = HttpRequest.CreatePostHttpResponse(url, parameters, Encoding.UTF8);

            Stream streamReceive = response.GetResponseStream();
            Encoding encoding = Encoding.UTF8;

            StreamReader streamReader = new StreamReader(streamReceive, encoding);
            string strResult = streamReader.ReadToEnd();
            streamReceive.Dispose();
            streamReader.Dispose();

            DataModel.ShortUrl result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ShortUrl>(strResult);

            if (result.errcode != 0)
            {
                Output = result.message;
                Loggers.WeinXinLogger.ErrorFormat("ConvertShortUrl ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("ConvertShortUrl ==> 请求结果：{0}", result.ToString());
                return false;
            }
            else
            {
                Output = result.short_url;
                return true;
            }
        }
        
        /// <summary>
        /// 获取关注者列表，（关注者列表已返回完时，返回next_openid为空）
        /// </summary>
        /// <param name="next_openid"></param>
        /// <returns></returns>
        public static DataModel.SubscribeUser GetUser(string next_openid = null)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}", WeiXinConfig.AccessToken);

            if (!string.IsNullOrEmpty(next_openid)) url = string.Format("{0}&next_openid={1}", url, next_openid);
            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, string.Empty);
            DataModel.SubscribeUser result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.SubscribeUser>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("获取关注者列表，GetUser ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("获取关注者列表，GetUser ==> 请求结果：errcode={0}, errmsg={1}", result.errcode, result.errmsg);
                return null;
            }
            else
            {
                return result;
            }
        }

        /// <summary>
        /// 上传文件到微信服务器 （媒体文件在后台保存时间为3天，即3天后media_id失效。）
        ///      图片（image）: 1M，支持JPG格式
        ///      语音（voice）：2M，播放长度不超过60s，支持AMR\MP3格式
        ///      视频（video）：10MB，支持MP4格式
        ///      缩略图（thumb）：64KB，支持JPG格式 
        /// </summary>
        /// <param name="Type">媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb） </param>
        /// <param name="filepath">本地服务器的地址</param>
        /// <returns></returns>
        public static string UploadMultimedia(string Type, string filepath)
        {
            string result = "";
            string url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}", WeiXinConfig.AccessToken, Type);
            //string filepath = Server.MapPath("image") + "\\hemeng80.jpg"; (本地服务器的地址)
            WebClient client = new WebClient();
            client.Credentials = CredentialCache.DefaultCredentials;
            try
            {
                byte[] responseArray = client.UploadFile(url, "POST", filepath);
                result = System.Text.Encoding.Default.GetString(responseArray, 0, responseArray.Length);
                DataModel.Multimeida multimeida = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.Multimeida>(result);

                if (multimeida.errcode != 0)
                {
                    return null;
                }

                result = multimeida.media_id;
            }
            catch (Exception ex)
            {
                Loggers.WeinXinLogger.FatalFormat("上传文件到微信服务器失败：{0}", ex);
                return null;
            }

            Loggers.WeinXinLogger.InfoFormat("上传MediaId：{0}", result);
            return result;
        }

        /// <SUMMARY> 
        /// 下载保存多媒体文件,返回多媒体保存路径 
        /// </SUMMARY> 
        /// <PARAM name="media_id">媒体文件ID </PARAM> 
        /// <RETURNS></RETURNS> 
        public static string GetMultimedia(string media_id)
        {
            string file = string.Empty;
            string content = string.Empty;
            string strpath = string.Empty;
            string savepath = string.Empty;
            string url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + WeiXinConfig.AccessToken + "&media_id=" + media_id;

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);

            req.Method = "GET";
            using (WebResponse webResponse = req.GetResponse())
            {
                HttpWebResponse response = (HttpWebResponse)webResponse;

                strpath = response.ResponseUri.ToString();
                WebClient client = new WebClient();
                savepath = System.Web.HttpContext.Current.Server.MapPath("image") + "\\" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next().ToString().Substring(0, 4) + ".jpg";
                try
                {
                    client.DownloadFile(strpath, savepath);
                    file = savepath;
                }
                catch (Exception ex)
                {
                    Loggers.WeinXinLogger.FatalFormat("从微信服务器下载文件失败：{0}", ex);
                    return null;
                }
            }
            return file;
        }

        /// <summary>
        /// 上传图文消息素材  （图文、文本、语音、图片）
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static DataModel.Multimeida UploadNews(DataModel.News item)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(item));
            DataModel.Multimeida result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.Multimeida>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("上传图文消息素材 ，UploadNews ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("上传图文消息素材 ，UploadNews ==> 请求结果：{0}", result);
                return null;
            }
            else
            {
                return result;
            }
        }

        /// <summary>
        /// 上传视频消息素材
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static DataModel.Multimeida UploadVideo(DataModel.Video item)
        {
            string url = string.Format("https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(item));
            DataModel.Multimeida result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.Multimeida>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("上传图文消息素材 ，UploadVideo ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("上传图文消息素材 ，UploadVideo ==> 请求结果：errcode={0}, errmsg={1}", result.errcode, result.errmsg);
                return null;
            }
            else
            {
                return result;
            }
        }

        /// <summary>
        /// 根据OpenID列表群发，如要发送图文消息，需执行UploadNews；如要上传视频需执行UploadVideo，使用返回的media_id发送
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static DataModel.ResultMsg SendMessageByOpenId(DataModel.SendMessage item)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(item));

            DataModel.ResultMsg result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("根据OpenID列表群发 ，SendMessageByOpenId ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("根据OpenID列表群发 ，SendMessageByOpenId ==> 请求结果：{0}", result.ToString());
            }
            else
            {
                Loggers.WeinXinLogger.InfoFormat("根据OpenID列表群发 ，SendMessageByOpenId ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.InfoFormat("根据OpenID列表群发 ，SendMessageByOpenId ==> 请求结果：{0}", result.ToString());
            }
            return result;
        }

        /// <summary>
        /// 根据分组ID群发，如要发送图文消息，需执行UploadNews；如要上传视频需执行UploadVideo，使用返回的media_id发送
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static DataModel.ResultMsg SendMessageByFilter(DataModel.SendMessage item)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(item));
            DataModel.ResultMsg result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("根据分组ID群发 ，SendMessageByFilter ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("根据分组ID群发 ，SendMessageByFilter ==> 请求结果：{0}", result.ToString());
            }
            else
            {
                Loggers.WeinXinLogger.InfoFormat("根据分组ID群发 ，SendMessageByFilter ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.InfoFormat("根据分组ID群发 ，SendMessageByFilter ==> 请求结果：{0}", result.ToString());
            }
            return result;
        }

        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="TemplateId"></param>
        /// <param name="OpenId"></param>
        /// <param name="Url"></param>
        /// <param name="Data"></param>
        /// <returns></returns>
        public static DataModel.ResultMsg SentTemplateMsg<T>(string TemplateId, string OpenId, string Url, T Data) where T : new()
        {
            if (string.IsNullOrEmpty(TemplateId))
            {
                return new DataModel.ResultMsg() { errcode = 50001 };
            }

            DataModel.TemplateMsg<T> template = new DataModel.TemplateMsg<T>();
            template.touser = OpenId;
            template.template_id = TemplateId;
            template.url = Url;
            template.topcolor = "#FF0000";
            template.data = Data;

            string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(template));
            DataModel.ResultMsg result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);

            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("发送模板消息 ，SentTemplateMsg ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("发送模板消息 ，SentTemplateMsg ==> 请求结果：{0}", result.ToString());
            }
            return result;
        }

        /// <summary>
        /// 发送客服消息
        /// </summary>
        /// <param name="msg">客服消息</param>
        /// <param name="Output">返回信息</param>
        /// <returns></returns>
        public static bool SentServiceInfo(DataModel.AsyncMessage msg, out string Output)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}", WeiXinConfig.AccessToken);

            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, Newtonsoft.Json.JsonConvert.SerializeObject(msg));
            DataModel.ResultMsg result = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);

            Output = result.message;
            if (result.errcode != 0)
            {
                Loggers.WeinXinLogger.ErrorFormat("发送客服消息，SentServiceInfo ==> 请求地址：{0}", url);
                Loggers.WeinXinLogger.ErrorFormat("发送客服消息，SentServiceInfo ==> 请求结果：{0}", result.ToString());
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 创建微信菜单
        /// </summary>
        /// <param name="MenuList"></param>
        /// <returns></returns>
        public static string CreateMenu(DataModel.Menu Menu)
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}", WeiXinConfig.AccessToken);
            JavaScriptSerializer js = new JavaScriptSerializer();            
            js.RegisterConverters(new JavaScriptConverter[] { new DataModel.ButtonJSConverter() });
            string json = js.Serialize(Menu);
            Loggers.WeinXinLogger.Info(json);
            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, json);
            DataModel.ResultMsg resultMsg = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);
            Loggers.WeinXinLogger.Info(resultMsg.ToString());
            return resultMsg.message;
        }

        /// <summary>
        /// 删除微信菜单
        /// </summary>
        /// <returns></returns>
        public static string DeleteMenu()
        {
            string url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}", WeiXinConfig.AccessToken);
            var client = new WebClient();
            client.Headers["Content-Type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var strResult = client.UploadString(url, string.Empty);
            DataModel.ResultMsg resultMsg = Newtonsoft.Json.JsonConvert.DeserializeObject<DataModel.ResultMsg>(strResult);
            Loggers.WeinXinLogger.InfoFormat("删除公众号菜单，{0}", resultMsg.ToString());
            return resultMsg.message;
        }
    }
}
